package user

import (
	"5title_gin/global"
	"5title_gin/internal/api/middleware"
	"5title_gin/internal/model/user"
	redis_ser2 "5title_gin/pkg/redis_ser"
	"5title_gin/pkg/utils/jwts"
	"5title_gin/pkg/utils/pwd"
	"5title_gin/pkg/utils/res"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
	"time"
)

// LoginView 用户登录
// @Tags 用户管理
// @Summary 用户登录
// @Description 用户登录
// @Param data body LoginRequest true "参数"
// @Router /api/users/login [post]
// @Produce json
// @Success 200 {object} res.Response
func (UserApi) LoginView(c *gin.Context) {
	cr := middleware.GetBind[user.LoginRequest](c)

	// 检查锁定状态
	locked, err := redis_ser2.CheckLock(cr.Username)
	if err != nil {
		res.FailWithMsg("系统错误，请稍后再试！", c)
		return
	}
	if locked {
		res.FailWithMsg("账号已锁定，请稍后再试！", c)
		return
	}

	// 查询用户
	var _user user.UserModel
	if err := global.DB.Where("username = ?", cr.Username).First(&_user).Error; err != nil {
		handleLoginFailure(cr.Username, c)
		return
	}

	// 验证密码
	if !pwd.CompareHashAndPassword(_user.Password, cr.Password) {
		handleLoginFailure(cr.Username, c)
		return
	}
	// 生成 Access Token
	accessToken, refreshToken, err := jwts.GenerateToken(jwts.Claims{
		RoleID: _user.RoleID,
		UserID: _user.ID,
	})
	if err != nil {
		res.FailWithMsg("生成 Access Token 失败", c)
		return
	}

	// 存储 Access Token 和 Refresh Token
	err = redis_ser2.StoreAccessToken(_user.ID, accessToken)
	if err != nil {
		res.Error("存储 Access Token 失败", err, c)
		return
	}
	err = redis_ser2.StoreRefreshToken(_user.ID, refreshToken)
	if err != nil {
		res.Error("存储 Refresh Token 失败", err, c)
		return
	}
	redis_ser2.SetUserInfo(_user.ID)

	// 更新最后登录时间
	_user.LastLogin = time.Now().Format("2006-01-02 15:04:05")
	if err := global.DB.Save(&_user).Error; err != nil {
		res.Error("更新最后登录时间失败", err, c)
		return
	}

	// 登录成功，清除失败记录
	if err := redis_ser2.ClearFailedAttempts(cr.Username); err != nil {
		res.Error("清除失败记录失败", err, c)
		return
	}
	var data = struct {
		AccessToken  string `json:"access_token"`
		RefreshToken string `json:"refresh_token"`
	}{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
	}

	// 返回成功响应
	res.Ok(data, "登录成功", c)
}
func handleLoginFailure(username string, c *gin.Context) {
	currentAttempts, maxAttempts, err := redis_ser2.IncrementFailedAttempts(username)
	if err != nil {
		res.FailWithMsg("系统错误，请稍后再试", c)
		return
	}
	remainingAttempts := maxAttempts - currentAttempts
	if remainingAttempts > 0 {
		res.FailWithMsg(fmt.Sprintf("用户名或密码错误，您还可以尝试 %d 次", remainingAttempts), c)
	} else {
		res.FailWithMsg("账号已锁定，请稍后再试！", c)
	}
}

// RefreshToken 刷新 Token
func (UserApi) RefreshToken(c *gin.Context) {

	var req struct {
		RefreshToken string `json:"refresh_token" binding:"required"`
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		res.Error("参数错误：refresh_token 缺失或无效", err, c)
		return
	}
	userClaims, err := jwts.GetClaimsFromToken(c)
	if err != nil {
		return
	}
	storedRefreshToken, err := redis_ser2.GetRefreshToken(userClaims.Claims.UserID)
	if err != nil || storedRefreshToken == "" {
		res.FailWithMsg("Refresh Token 未找到或已失效", c)
		return
	}
	// 验证 Refresh Token 是否匹配
	if storedRefreshToken != jwts.HashToken(req.RefreshToken) {
		res.FailWithMsg("Refresh Token 不匹配", c)
		return
	}
	// 解析 Refresh Token
	claims, err := jwts.CheckToken(req.RefreshToken)
	if err != nil {
		if errors.Is(err, jwt.ErrSignatureInvalid) {
			res.FailWithMsg("Refresh Token 签名无效", c)
		} else if err.Error() == "Token is expired" {
			res.FailWithMsg("Refresh Token 已过期", c)
		} else {
			res.FailWithMsg("解析 Refresh Token 失败", c)
		}
		return
	}

	// 生成新的 Access Token
	newAccessToken, _, err := jwts.GenerateToken(jwts.Claims{
		UserID: claims.Claims.UserID,
		RoleID: claims.Claims.RoleID,
	})
	if err != nil {
		res.Error("生成新的 Access Token 失败", err, c)
		return
	}
	// 存储新的 Access Token 到 Redis
	err = redis_ser2.StoreAccessToken(claims.Claims.UserID, newAccessToken)
	if err != nil {
		res.Error("存储新的 Access Token 失败", err, c)
		return
	}
	res.Ok(newAccessToken, "刷新成功", c)
}
